/*
 * Powered By XY
 * Since 2020
 */

package com.xy.biz.ts.service.impl;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

import com.xy.biz.base.client.DictClient;
import com.xy.biz.mc.client.MessagePushClient;
import com.xy.biz.mc.domain.Message;
import com.xy.biz.mc.domain.consts.MessageTypeConstant;
import com.xy.biz.mc.domain.req.MessagePushRequest;
import com.xy.biz.ts.domain.bo.TrainBO;
import com.xy.biz.ts.domain.bo.TrainFlowConstants;
import com.xy.biz.ts.domain.bo.TrainFlowHandleBO;
import com.xy.biz.ts.domain.converter.TrainConverter;
import com.xy.biz.ts.domain.converter.TrainSumConverter;
import com.xy.biz.ts.domain.po.TrainSumPO;
import com.xy.biz.ts.domain.query.TrainFlowHandleQuery;
import com.xy.biz.ts.domain.req.HandleTrainSumFlowRequest;
import com.xy.biz.ts.domain.req.HandleTrainSumReleaseFlowRequest;
import com.xy.biz.ts.domain.resp.GetTrainResponse;
import com.xy.biz.ts.domain.resp.GetTrainSumResponse;
import com.xy.biz.ts.manager.TrainFlowHandleManager;
import com.xy.biz.ts.manager.TrainManager;
import com.xy.biz.uc.client.UserClient;
import com.xy.biz.uc.domain.dto.UserDTO;
import com.xy.biz.uc.domain.req.GetUserRequest;
import com.xy.lang.domain.Page;
import com.xy.lang.util.CalendarUtils;
import com.xy.lang.util.ResultUtils;
import com.xy.tool.context.UserContextHolder;
import com.xy.tool.gid.service.GidService;
import com.xy.tool.json.JsonUtils;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.xy.lang.domain.Result;
import com.xy.biz.ts.domain.bo.TrainSumBO;
import com.xy.biz.ts.domain.query.TrainSumQuery;
import com.xy.biz.ts.service.TrainSumService;
import com.xy.biz.ts.manager.TrainSumManager;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

/**
 * @author zgy
 * @date 2021-7-29
 */
@Service
public class TrainSumServiceImpl implements TrainSumService {

    @Autowired
    private TrainSumManager trainSumManager;
    @Autowired
    private MessagePushClient messagePushClient;
    @Autowired
    private TrainFlowServiceSupport trainFlowServiceSupport;
    @Autowired
    private TrainFlowHandleManager trainFlowHandleManager;
    @Autowired
    private UserClient userClient;
    @Autowired
    private GidService gidService;
    @Autowired
    private TaskService taskService;
    @Autowired
    private RuntimeService runtimeService;
    @Autowired
    private DictClient dictClient;
    @Autowired
    private TrainManager trainManager;

    @Override
    public Result<?> saveTrainSum(TrainSumBO trainSumBO) {
        build(trainSumBO);
        //开始新建培训总结的流程
        trainSumBO.setPhase(TrainFlowConstants.PHASE_APPLY);
        Task task = trainFlowServiceSupport.startFirstTask(trainSumBO, TrainFlowConstants.PROCESS_TRAINING_SUMMARY_PROGRESS, trainSumBO.getHandleUserId());
        trainSumBO.setForeignKey(task.getProcessInstanceId());
        TrainFlowHandleBO.build(trainSumBO, UserContextHolder.getUserId(), UserContextHolder.getUserGroupId(), TrainFlowConstants.PHASE_APPLY, TrainFlowConstants.HANDLE_RESULT_ACCEPT, true, null);
        //保存培训总结及培训节点
        TrainSumPO trainSumPO = trainSumManager.saveTrainSum(trainSumBO);
        if (!ObjectUtils.isEmpty(trainSumPO)) {
            //发送消息
            createMessage(trainSumBO.getCreateUserId(), trainSumBO.getHandleUserId(), TrainFlowConstants.HANDLE_RESULT_ACCEPT);
            return Result.success();
        }
        return Result.ofErrorRowsAffected();
    }

    /**
     * 主管领导审批
     *
     * @param request
     */
    @Override
    public Result<?> adminAudit(HandleTrainSumFlowRequest request) {
        LocalDateTime now = LocalDateTime.now();
        TrainSumBO trainSum = trainSumManager.getTrainSum(request.getTrainSumId());
        trainSum.setPhase(request.getPhase());
        if (Objects.equals(request.getResult(), TrainFlowConstants.HANDLE_RESULT_ACCEPT)) {
            TrainFlowHandleBO trainFlowHandleBO = TrainFlowHandleBO.build(trainSum, UserContextHolder.getUserId(), UserContextHolder.getUserGroupId(), request.getPhase(), TrainFlowConstants.HANDLE_RESULT_ACCEPT, true, request.getOpinion());
            trainFlowHandleManager.saveTrainFlowHandle(trainFlowHandleBO);
            trainFlowServiceSupport.gotoNextTask(trainSum, request.getNextHandleUserId(), TrainFlowConstants.HANDLE_RESULT_ACCEPT);
        } else {
            UserDTO userDTO = ResultUtils.get(userClient.getUser(GetUserRequest.builder().userId(trainSum.getCreateUserId()).withUserGroup(true).build()));
            TrainFlowHandleBO trainFlowHandleBO = TrainFlowHandleBO.build(trainSum, trainSum.getCreateUserId(), userDTO.getUserGroup().getId(), TrainFlowConstants.PHASE_ADMINAUDIT, TrainFlowConstants.HANDLE_RESULT_END, true, request.getOpinion());
            trainFlowHandleManager.saveTrainFlowHandle(trainFlowHandleBO);
            trainFlowServiceSupport.finish(trainSum);
        }
        trainSum.setUpdateTime(now);
        int row = trainSumManager.updateTrainSum(trainSum);
        if (row > 0) {
            createMessage(request.getNextHandleUserId(), trainSum.getCreateUserId(), request.getResult());
        }
        return Result.success();
    }

    /**
     * 人事行政部意见
     *
     * @param request
     */
    @Override
    public Result<?> opinion(HandleTrainSumReleaseFlowRequest request) {
        LocalDateTime now = LocalDateTime.now();
        TrainSumBO trainSum = trainSumManager.getTrainSum(request.getTrainSumId());
        if (Objects.equals(request.getResult(), TrainFlowConstants.HANDLE_RESULT_ACCEPT)) {
            trainSum.setPhase(TrainFlowConstants.PHASE_RELEASE);
            TrainFlowHandleBO trainFlowHandleBO = TrainFlowHandleBO.build(trainSum, UserContextHolder.getUserId(), UserContextHolder.getUserGroupId(), TrainFlowConstants.PHASE_RELEASE, TrainFlowConstants.HANDLE_RESULT_ACCEPT, true, request.getOpinion());
            trainFlowHandleManager.saveTrainFlowHandle(trainFlowHandleBO);
            trainFlowServiceSupport.finishLastTask(trainSum);
        } else {
            trainSum.setPhase(request.getPhase());
            UserDTO userDTO = ResultUtils.get(userClient.getUser(GetUserRequest.builder().userId(trainSum.getCreateUserId()).withUserGroup(true).build()));
            TrainFlowHandleBO trainFlowHandleBO = TrainFlowHandleBO.build(trainSum, trainSum.getCreateUserId(), userDTO.getUserGroup().getId(), TrainFlowConstants.PHASE_OPINION, TrainFlowConstants.HANDLE_RESULT_END, true, request.getOpinion());
            trainFlowHandleManager.saveTrainFlowHandle(trainFlowHandleBO);
            trainSum.setPhase(TrainFlowConstants.PHASE_OPINION);
            trainFlowServiceSupport.finish(trainSum);
        }
        trainSum.setUpdateTime(now);
        int row = trainSumManager.updateTrainSum(trainSum);
        if (row > 0) {
            createMessage(trainSum.getCreateUserId(), trainSum.getCreateUserId(), request.getResult());
        }
        return Result.success();
    }

    /**
     * 培训总结待办
     *
     * @param query
     */
    @Override
    public Page<GetTrainSumResponse> searchTrainSumFlowTodo(TrainFlowHandleQuery query) {
        List<TrainSumBO> trainSumBOS = new ArrayList<>();
        List<String> flow = new ArrayList<>();
        //查询培训流程
        flow.add(TrainFlowConstants.PROCESS_TRAINING_SUMMARY_PROGRESS);
        long total = taskService.createTaskQuery()
                .taskAssignee(UserContextHolder.getUserId().toString())
                .processDefinitionKeyIn(flow)
                .count();
        if (total > 0) {
            List<Task> taskList = taskService.createTaskQuery()
                    .taskAssignee(UserContextHolder.getUserId().toString())
                    .processDefinitionKeyIn(flow)
                    .orderByTaskCreateTime()
                    .desc()
                    .listPage(query.getOffset(), query.getRows());

            if (!CollectionUtils.isEmpty(taskList)) {
                Set<String> processInstanceIdSet = taskList.stream().map(Task::getProcessInstanceId).collect(Collectors.toSet());
                List<ProcessInstance> processInstanceList = runtimeService.createProcessInstanceQuery().processInstanceIds(processInstanceIdSet).list();
                Set<Long> trainSumFlowIdSet = processInstanceList.stream().map(e -> Long.parseLong(e.getBusinessKey())).collect(Collectors.toSet());
                trainSumBOS = trainSumManager.listTrainSumById(trainSumFlowIdSet);
                if (CollectionUtils.isEmpty(trainSumBOS)) {
                    return null;
                }
            }
        }
        Set<Long> trainIds = trainSumBOS.stream().map(TrainSumBO::getTrainId).collect(Collectors.toSet());
        Map<Long, String> trainMap = new HashMap<>();
        if (!CollectionUtils.isEmpty(trainIds)) {
            trainMap = trainManager.listTrainById(trainIds).stream().collect(Collectors.toMap(TrainBO::getTrainId, t -> t.getName()));
        }
        Map<Long, String> finalTrainMap = trainMap;
        trainSumBOS = trainSumBOS.stream().peek(t -> {
            t.setPhaseName(TrainFlowConstants.FLOW_TYPE_SUM);
            t.setTrainName(finalTrainMap.get(t.getTrainId()));
            t.setPhaseNum(TrainFlowConstants.getPhaseNum(t.getPhase()));
        }).collect(Collectors.toList());
        userClient.buildByUser(trainSumBOS,
                trainSumBOS.stream().map(TrainSumBO::getCreateUserId).collect(Collectors.toSet()),
                TrainSumBO::getCreateUserId,
                (t, user) -> t.setCreateUserName(user.getUserName())
        );
        userClient.buildByUser(trainSumBOS,
                trainSumBOS.stream().map(TrainSumBO::getSumUserId).collect(Collectors.toSet()),
                TrainSumBO::getSumUserId,
                (t, user) -> t.setSumUserName(user.getUserName())
        );
        List<GetTrainSumResponse> getTrainSumResponses = TrainSumConverter.toResponse(trainSumBOS);
        Collections.sort(getTrainSumResponses, Comparator.comparing(GetTrainSumResponse::getUpdateTime).reversed());
        return new Page(getTrainSumResponses, (int) total);
    }

    private void build(TrainSumBO trainSumBO) {
        Long userId = UserContextHolder.getUserId();
        LocalDateTime now = LocalDateTime.now();
        trainSumBO.setTrainSumId(gidService.generate());
        trainSumBO.setTenantId(UserContextHolder.getTenantId());
        trainSumBO.setSumUserId(userId);
        trainSumBO.setCreateUserId(userId);
        if (!trainSumBO.getCertificateFlag()) {
            trainSumBO.setCertificateName(null);
        }
        trainSumBO.setCreateTime(now);
        trainSumBO.setUpdateTime(now);
        trainSumBO.setDeleteFlag(false);
    }

    @Override
    public Result<?> saveAllTrainSum(Collection<TrainSumBO> collection) {
        int affectedRows = trainSumManager.saveAllTrainSum(collection);
        if (affectedRows > 0) {
            return Result.success();
        }
        return Result.ofErrorRowsAffected();
    }

    @Override
    public Result<?> updateTrainSum(TrainSumBO trainSumBO) {
        int affectedRows = trainSumManager.updateTrainSum(trainSumBO);
        if (affectedRows > 0) {
            return Result.success();
        }
        return Result.ofErrorRowsAffected();
    }

    @Override
    public Result<?> deleteTrainSum(Long trainSumId) {
        int affectedRows = trainSumManager.deleteTrainSum(trainSumId);
        if (affectedRows > 0) {
            return Result.success();
        }
        return Result.ofErrorRowsAffected();
    }

    @Override
    public TrainSumBO getTrainSum(Long trainSumId) {
        return trainSumManager.getTrainSum(trainSumId);
    }

    @Override
    public List<TrainSumBO> listTrainSumById(Collection<Long> collection) {
        return trainSumManager.listTrainSumById(collection);
    }

    @Override
    public List<TrainSumBO> listTrainSum(TrainSumQuery query) {
        return trainSumManager.listTrainSum(query);
    }

    @Override
    public int countTrainSum(TrainSumQuery query) {
        return trainSumManager.countTrainSum(query);
    }

    private void createMessage(Long NextHandleUserId, Long createUserId, int result) {
        //发送消息
        //通过
        if (Objects.equals(result, TrainFlowConstants.HANDLE_RESULT_ACCEPT)) {
            //发送消息
            //定义消息内容
            Message message = Message.builder()
                    .type(MessageTypeConstant.TYPE_FLOW)
                    .data(1)
                    .remark("新增培训总结流程-审核")
                    .path(MessageTypeConstant.FLOW_LIST)
                    .build();
            sendMessage(message, NextHandleUserId);
        } else {//拒绝通过
            //定义消息内容
            Message message = Message.builder()
                    .type(MessageTypeConstant.TYPE_FLOW)
                    .data(1)
                    .remark("新增培训总结流程-审核不通过")
                    .path(MessageTypeConstant.FLOW_LIST)
                    .build();
            sendMessage(message, createUserId);
        }
    }

    /**
     * 发送信息
     * @param message
     * @param toId
     */
    protected void sendMessage(Message message, Long toId) {
        messagePushClient.send(MessagePushRequest.builder()
                .data(JsonUtils.toJson(message).getBytes())
                .dataType(0)
                .expiredSeconds(0L)
                .toId(toId)
                .offlineFlag(true).build());
    }

}
